#include "um.client.h"

#include <cstring>

TOB::UM::Client::Client(Nameserver::IP nsip, std::string username, std::string password) : TOB::AuthRequired(nsip, username, password) {
  std::string NSHost;
  TOB::Nameserver::convertIP(nsip, NSHost);
  
  TOB::Nameserver ns = TOB::Nameserver(NSHost);
  nsconnected = (ns.requestAddress(Server::UserManagement, UMIP) == Code::Okay);
  ns.convertIP(UMIP, UMHost);
  
  if (!nsconnected) {
    connected = false;
  }
  else {
    // connect to server
    clnt = clnt_create(UMHost.c_str(), UM_PROG, UM_VERSION, "udp");
    connected = (clnt != NULL);
  }
}

TOB::UM::Client::~Client() {
  if (clnt == NULL && connected) {
      clnt_destroy(clnt);
    }
}

Code::Type TOB::UM::Client::changeFieldByLogin(std::string login, std::string field, std::string value) {
  if (!nsconnected) {
    return Code::NS_DoesntRespond;
  }
  if (!connected) {
    return Code::UM_DoesntRespond;
  }
  
  Field_UM_RPC fld;
  int length = username.length();
  memcpy(fld.user.username, username.c_str(), (length > 32) ? 32 : length + 1);
  fld.user.username[32] = 0;
  
  length = password.length();
  memcpy(fld.user.password, password.c_str(), (length > 32) ? 32 : length + 1);
  fld.user.password[32] = 0;
  
  fld.user.nsip = static_cast<int>(nsip);
  
  length = login.length();
  memcpy(fld.login, login.c_str(), (length > 32) ? 32 : length + 1);
  fld.login[32] = 0;
  
  length = field.length();
  memcpy(fld.field, field.c_str(), (length > 32) ? 32 : length + 1);
  fld.field[32] = 0;
  
  length = value.length();
  memcpy(fld.value, value.c_str(), (length > 32) ? 32 : length + 1);
  fld.value[32] = 0;
  
  int* respond = NULL;
  respond = changefield_1(&fld, clnt);
  if (respond == NULL || !connected) {
    return Code::UM_DoesntRespond;
  }
  
  return static_cast<Code::Type>(*respond);
}

Code::Type TOB::UM::Client::createUser(std::string login, std::string pass, std::string role, std::string policy, std::string name) {
  if (!nsconnected) {
    return Code::NS_DoesntRespond;
  }
  if (!connected) {
    return Code::UM_DoesntRespond;
  }
  
  UserRec_UM_RPC user;
  
  int length = username.length();
  memcpy(user.user.username, username.c_str(), (length > 32) ? 32 : length + 1);
  user.user.username[32] = 0;
  
  length = password.length();
  memcpy(user.user.password, password.c_str(), (length > 32) ? 32 : length + 1);
  user.user.password[32] = 0;
  
  user.user.nsip = static_cast<int>(nsip);
  
  length = login.length();
  memcpy(user.login, login.c_str(), (length > 32) ? 32 : length + 1);
  user.login[32] = 0;
  
  length = pass.length();
  memcpy(user.password, pass.c_str(), (length > 32) ? 32 : length + 1);
  user.password[32] = 0;
  
  length = role.length();
  memcpy(user.role, role.c_str(), (length > 20) ? 20 : length + 1);
  user.role[20] = 0;
  
  length = policy.length();
  memcpy(user.policy, policy.c_str(), (length > 255) ? 255 : length + 1);
  user.policy[255] = 0;
  
  length = name.length();
  memcpy(user.name, name.c_str(), (length > 255) ? 255 : length + 1);
  user.name[255] = 0;
  
  int* respond = NULL;
  respond = adduser_1(&user, clnt);
  if (respond == NULL || !connected) {
    return Code::UM_DoesntRespond;
  }
  
  return static_cast<Code::Type>(*respond);
}

Code::Type TOB::UM::Client::deleteUser(std::string login) {
  if (!nsconnected) {
    return Code::NS_DoesntRespond;
  }
  if (!connected) {
    return Code::UM_DoesntRespond;
  }
  
  Field_UM_RPC field;
  int length = username.length();
  memcpy(field.user.username, username.c_str(), (length > 32) ? 32 : length + 1);
  field.user.username[32] = 0;
  
  length = password.length();
  memcpy(field.user.password, password.c_str(), (length > 32) ? 32 : length + 1);
  field.user.password[32] = 0;
  
  field.user.nsip = static_cast<int>(nsip);
  
  length = login.length();
  memcpy(field.login, login.c_str(), (length > 32) ? 32 : length + 1);
  field.login[32] = 0;
  
  int* respond = NULL;
  respond = deleteuser_1(&field, clnt);
  if (respond == NULL || !connected) {
    return Code::UM_DoesntRespond;
  }
  
  return static_cast<Code::Type>(*respond);
}
